#ifndef _DATA_H_
#define _DATA_H_

#include "Include.h"
#include "Settings.h"

class DOUBLE_BASE
{
 private:

    double dValue[2]; 

protected:

	double GetD1()
	{
		return dValue[0];
	}

	double GetD2()
	{
		return dValue[1];
	}

	void SetD1(double d)
	{
		dValue[0] = d;
	}

	void SetD2(double d)
	{
		dValue[1] = d;
	}

 public:
	DOUBLE_BASE();
    DOUBLE_BASE(double d1 , double d2);
	DOUBLE_BASE(const DOUBLE_BASE& db);


    friend bool operator == (const DOUBLE_BASE & db1, const DOUBLE_BASE & db2);
    const DOUBLE_BASE& operator=(const DOUBLE_BASE & db);

	virtual std::string Dump() = 0;

};

class _PROCESS_CMD
{
public:
	std::string cmd;
	_PROCESS_TYPE type;

	_PROCESS_CMD(const std::string& cmd , const _PROCESS_TYPE type)
	{
		this->cmd = cmd;
		this->type = type;
	}

	_PROCESS_CMD(const _PROCESS_CMD& c)
	{
		this->cmd = c.cmd;
		this->type = c.type;
	}

	const _PROCESS_CMD& operator=(const _PROCESS_CMD & c)
	{
		if (this != &c) 
		{
			this->cmd = c.cmd;
			this->type = c.type;
		}
		return *this;
	}

};

class _PROCESS_INFO
{
public:
	int pid;
	time_t start_time;

	_PROCESS_INFO(const int pid)
	{
		this->pid = pid;
		this->start_time = time(NULL);
	}

	_PROCESS_INFO(const _PROCESS_INFO& i)
	{
		this->pid = i.pid;
		this->start_time = i.start_time;
	}

	const _PROCESS_INFO& operator=(const _PROCESS_INFO & i)
	{
		if (this != &i) 
		{
			this->pid = i.pid;
			this->start_time = i.start_time;
		}
		return *this;
	}

	friend bool operator == (const _PROCESS_INFO & info1, const _PROCESS_INFO& info2)
	{
		return info1.pid == info2.pid;
	}

	friend bool operator == (const _PROCESS_INFO & info1, const int pid)
	{
		return info1.pid == pid;
	}

	friend bool operator == (const int pid , const _PROCESS_INFO & info2)
	{
		return pid == info2.pid;
	}


	int GetElapsedSec()
	{
		return time(NULL) - start_time;
	}

};


class _TIME : public DOUBLE_BASE
{

public:

	_TIME() : DOUBLE_BASE(){};
	_TIME(const _TIME& t) : DOUBLE_BASE(t){};
	_TIME(double start , double duration) : DOUBLE_BASE(start , duration){};

	const _TIME& operator+=( _TIME & t);

	double GetStart()
	{
		return GetD1();
	}

	double GetDuration()
	{
		return GetD2();
	}

	void SetStart(double start)
	{
		SetD1(start);
	}

	void SetDuration(double duration)
	{
		SetD2(duration);
	}


	double GetEnd()
	{
		return GetD1() + GetD2();
	}

	std::string Dump()
	{
		char buf[100];
		sprintf(buf , "Start Time :%.2f , duration : %.2f" , GetStart() , GetDuration());
		return buf;
	}


};

class _SIZE : public DOUBLE_BASE
{

public:

	_SIZE() : DOUBLE_BASE(){};
	_SIZE(const _SIZE& s) : DOUBLE_BASE(s){};
	_SIZE(double width , double height) : DOUBLE_BASE(width , height){};


	double GetWidth()
	{
		return GetD1();
	}

	double GetHeight()
	{
		return GetD2();
	}

	void SetWidth(double width)
	{
		SetD1(width);
	}

	void SetHeight(double height)
	{
		SetD2(height);
	}

	std::string Dump()
	{
		char buf[100];
		sprintf(buf , "SIZE ( %.2f , %.2f ) " , GetWidth() , GetHeight());
		return buf;
	}


};

class _RESOLUTION : public DOUBLE_BASE
{

public:

	_RESOLUTION() : DOUBLE_BASE(){};
	_RESOLUTION(const _RESOLUTION& r) : DOUBLE_BASE(r){};
	_RESOLUTION(int width , int height) : DOUBLE_BASE(width , height){};


	int GetWidth()
	{
		return (int)GetD1();
	}

	int GetHeight()
	{
		return (int)GetD2();
	}

	void SetWidth(int width)
	{
		SetD1(width);
	}

	void SetHeight(int height)
	{
		SetD2(height);
	}

	std::string Dump()
	{
		char buf[100];
		sprintf(buf , "RESOLUTION ( %d , %d ) " , GetWidth() , GetHeight());
		return buf;
	}


};

class _POSITION : public DOUBLE_BASE
{

public:

	_POSITION() : DOUBLE_BASE(){};
	_POSITION(const _POSITION& p) : DOUBLE_BASE(p){};
	_POSITION(double x , double y) : DOUBLE_BASE(x , y){};


	double GetX()
	{
		return GetD1();
	}

	double GetY()
	{
		return GetD2();
	}

	void SetX(double x)
	{
		SetD1(x);
	}

	void SetY(double y)
	{
		SetD2(y);
	}

	std::string Dump()
	{
		char buf[100];
		sprintf(buf , "POS (%.2f , %.2f) " , GetX() , GetY());
		return buf;
	}


};

typedef enum{_EFFECT , _BLEND , _CURVE , _TEMP} _OBJ_TYPE;
class _OBJ_INFO
{
private:
	_TIME time;
	_POSITION pos;
	_SIZE size;

	double rotation;
	double alpha;

	std::string blending;
	double opacity;

	bool animation;
	_OBJ_TYPE type;

public:

	std::string obj_path;
	std::string sound_path;


	_OBJ_INFO();
	_OBJ_INFO(const _OBJ_INFO& o);
	_OBJ_INFO( const std::string& effect_path , const std::string& sound_path , const _TIME& t , const _POSITION& p , const _SIZE& s , const double a , const double r);
	_OBJ_INFO(const std::string& filter_path , const std::string& blending  , const double opacity);
	_OBJ_INFO(const std::string& curve_path);

	void SetAnimationTmpFileName(const int width , const int height , const std::string& filename);

	bool IsNonInput()
	{
		bool ret = false;

		switch(type)
		{
		case _CURVE:
			ret = true;
			break;
		default:
			ret = false;
		}

		return ret;

	}

	bool IsFilter()
	{
		return type != _EFFECT && type != _TEMP;
	}

	bool HasSound()
	{
		return sound_path.length() > 0;
	}

	_OBJ_TYPE GetType()
	{
		return type;
	}

	bool IsAnimation()
	{
		return animation;
	}

	_TIME& GetTime()
	{
		return time;
	}

	void SetTime(const _TIME & time)
	{
		this->time = time;
	}

	_POSITION& GetPosition()
	{
		return pos;
	}

	void SetPosition(const _POSITION & pos)
	{
		this->pos = pos;
	}

	_SIZE& GetSize()
	{
		return size;
	}

	void SetSize(const _SIZE & size)
	{
		this->size = size;
	}

	double GetAlpha()
	{
		return alpha;
	}

	void SetAlpha(double a)
	{
		alpha = a;
	}

	double GetRotation()
	{
		return rotation;
	}

	void SetRotation(double r)
	{
		rotation = r;
	}

	std::string GetBlending()
	{
		return this->blending;
	}

	double GetOpacity()
	{
		return this->opacity;
	}


	std::string GetObjPath()
	{
		return obj_path;
	}

	std::string GetSoundPath()
	{
		return sound_path;
	}


	static std::string GetBlankImgPath()
	{
		return std::string(Settings::GetSettings()->ADD_DIR) + BLANK_IMG;
	}

	static std::string GetSilentSoundPath()
	{
		return std::string(Settings::GetSettings()->ADD_DIR) + SILENT_SOUND;
	}




    const _OBJ_INFO& operator=(const _OBJ_INFO & o);

	std::string Dump()
	{
		char buf[1024];

		switch(type)
		{
			case _EFFECT:
				sprintf(buf , "effect[%s] :%s %s %s %s , alpha: %.2f , rotation: %.2f" 
					,obj_path.c_str(), sound_path.c_str(), time.Dump().c_str() , size.Dump().c_str() , pos.Dump().c_str() , GetAlpha() , GetRotation());
				break;
			case _BLEND:
				sprintf(buf , "blend[%s] :%s opacity: %.1f" ,obj_path.c_str(), blending.c_str() , opacity);
				break;
			case _CURVE:
				sprintf(buf , "curve[%s]" ,obj_path.c_str());
				break;
			case _TEMP:
				sprintf(buf , "temp[%s] :%s %s %s %s , alpha: %.2f , rotation: %.2f" 
					,obj_path.c_str(), sound_path.c_str(), time.Dump().c_str() , size.Dump().c_str() , pos.Dump().c_str() , GetAlpha() , GetRotation());
				break;
			default:
				ACE_ASSERT(false);
		}
		


		return buf;
	}

};

class _WORK_RESULT
{
public:
	_WORK_RESULT_TYPE result_type;
	std::string msg;

public:


	void print()
	{
		printf("%s\n" , msg.c_str());
	}

	void Set(_WORK_RESULT_TYPE result_type , const std::string& msg)
	{
		this->result_type = result_type;
		this->msg = msg;

	}


	_WORK_RESULT(_WORK_RESULT_TYPE result_type , const std::string& msg)
	{
		this->result_type = result_type;
		this->msg = msg;
	}

	_WORK_RESULT(const _WORK_RESULT& w)
	{
		this->result_type = w.result_type;
		this->msg = w.msg;
	}

	_WORK_RESULT()
	{
		this->result_type = WORK_RESULT_SUCCESS;
	}

	const _WORK_RESULT& operator=(const _WORK_RESULT& w)
	{
		if (this != &w) 
		{
			this->result_type = w.result_type;
			this->msg = w.msg;
		}
		return *this;
	}

	bool IsSuccess()
	{
		return WORK_RESULT_SUCCESS == this->result_type;
	}

	static std::string GetWorkTypeString(_WORK_RESULT_TYPE result_type)
	{
		std::string str;
		switch(result_type)
		{
		case WORK_RESULT_SUCCESS:
			str = "00";
			break;
		case WORK_RESULT_ERR_SCRIPT_STRUCTURE:
			str = "10";
			break;
		case WORK_RESULT_ERR_SCRIPT_CONTENT:
			str = "11";
			break;
		case WORK_RESULT_ERR_RENDERING_PARAM:
			str = "12";
			break;
		case WORK_RESULT_ERR_INVALID_PATH:
			str = "20";
			break;
		case WORK_RESULT_ERR_FILE_OPEN:
			str = "21";
			break;
		case WORK_RESULT_ERR_RENDERING_EXE:
			str = "30";
			break;
		case WORK_RESULT_ERR_RENDERER_DISCONNECT:
			str = "40";
			break;

		}

		return str;
	}


};

class _JOB_INFO
{
private:
	std::string jobId;

	std::string s3Url;

	std::string resultPath;

	std::string srcVideoPath;
	std::string srcScriptPath;

	std::string localVideoPath;
	std::string localScriptPath;

	double duration; 

	_RESOLUTION highResolution;
	_RESOLUTION middleResolution;
	_RESOLUTION lowResolution;

	int highBV;
	int middleBV;
	int lowBV;

	int highBA;
	int middleBA;
	int lowBA;



public:

	std::string GetJobId()
	{
		return jobId;
	}

	std::string GetS3Url()
	{
		return s3Url;
	}

	std::string GetResultPath()
	{
		return resultPath;
	}

	std::string GetSrcVideoFilePath(bool isFullPath)
	{
		return isFullPath ? s3Url + srcVideoPath : srcVideoPath;
	}

	std::string GetSrcScriptFilePath(bool isFullPath)
	{
		return isFullPath ? s3Url + srcScriptPath : srcScriptPath;
	}

	std::string GetResultSdVideoFilePath()
	{
		return s3Url + resultPath + "p01/" + jobId + ".mp4";
	}

	std::string GetResultMdVideoFilePath()
	{
		return s3Url + resultPath + "p02/" + jobId + ".mp4";
	}

	std::string GetResultHdVideoFilePath()
	{
		return s3Url + resultPath + "p03/" + jobId + ".mp4";
	}

	std::string GetResultHlsPath()
	{
		return s3Url + resultPath + "hls/";
	}

	void SetLocalVideoFilePath(const std::string& path)
	{
		this->localVideoPath = path;
	}

	std::string GetLocalVideoFilePath()
	{
		return localVideoPath;
	}

	void SetLocalScriptFilePath(const std::string& path)
	{
		this->localScriptPath = path;
	}

	std::string GetLocalScriptFilePath()
	{
		return localScriptPath;
	}

	std::string GetResultMobileThumbFilePath()
	{
		return s3Url + resultPath +jobId + "_m.jpg";
	}

	std::string GetResultWebThumbFilePath()
	{
		return s3Url + resultPath +jobId + "_w.jpg";
	}

	void SetResolution(Json::Value& root);

	_RESOLUTION& GetHighResolution()
	{
		return highResolution;
	}
	_RESOLUTION& GetMiddleResolution()
	{
		return middleResolution;
	}
	_RESOLUTION& GetLowResolution()
	{
		return lowResolution;
	}

	int GetHighBV()
	{
		return highBV;
	}
	int GetMiddleBV()
	{
		return middleBV;
	}
	int GetLowBV()
	{
		return lowBV;
	}

	int GetHighBA()
	{
		return highBA;
	}
	int GetMiddleBA()
	{
		return middleBA;
	}
	int GetLowBA()
	{
		return lowBA;
	}

	void SetBV(int h , int m , int l)
	{
		highBV = h;
		middleBV = m;
		lowBV = l;
	}
	void SetBA(int h , int m , int l)
	{
		highBA = h;
		middleBA = m;
		lowBA = l;
	}

	bool HasLowResolution()
	{
		return lowResolution.GetWidth() != 0;
	}


	double GetDuration()
	{
		return duration;
	}

	void SetDuration(const double duration)
	{
		this->duration = duration;
	}

	void Clear()
	{
		jobId = "";

		s3Url = "";
		resultPath = "";

		srcVideoPath = "";
		srcScriptPath = "";

		duration = 0.0;

	}

	_JOB_INFO()
	{
		Clear();
	}

	_JOB_INFO(const std::string& jobId ,const std::string& s3Url , const std::string& resultPath , const std::string& srcVideoPath , const std::string& srcScriptPath)
	{
		this->jobId = jobId;
		this->s3Url = s3Url;
		this->resultPath = resultPath;
		this->srcVideoPath = srcVideoPath;
		this->srcScriptPath = srcScriptPath;
	}

	_JOB_INFO(const _JOB_INFO& ji)
	{
		*this = ji;
	}

	const _JOB_INFO& operator=(const _JOB_INFO& ji)
	{
		if (this != &ji) 
		{
	
			this->jobId = ji.jobId;
			this->s3Url = ji.s3Url;
			this->resultPath = ji.resultPath;
			this->srcVideoPath = ji.srcVideoPath;
			this->srcScriptPath = ji.srcScriptPath;

			this->duration = ji.duration;

			this->highResolution = ji.highResolution;
			this->middleResolution = ji.middleResolution;
			this->lowResolution = ji.lowResolution;

			this->highBV = ji.highBV;
			this->middleBV = ji.middleBV;
			this->lowBV = ji.lowBV;

			this->highBA = ji.highBA;
			this->middleBA = ji.middleBA;
			this->lowBA = ji.lowBA;


		}
		return *this;
	}

	bool IsValid()
	{
		return jobId.length()  > 0;
	}



};

#define _PI_		3.1415926535898
class MATH
{
public:

	static int round(const double dv);

	static _SIZE GetRotationSize( _SIZE& org_size , const double rotation);
	static void ReplaceAll (std::string& strSrc, const std::string& strFind, const std::string& strDest);
	static void ConvertFilterPath(std::string & str);

	static bool IsImage(const std::string& path);
	static bool IsMovie(const std::string& path);
	static bool IsSameExt(std::string path , std::string ext);

	static double Truncate(double value , int float_size);

	static std::string CreateUUID();

	static void GetDate(int& year , int& month , int& day , const int pass);
	static void GetTime(int& hour , int& min , int& sec);
	static std::string GetDatePathString(const bool storage , const int pass);
	static std::string GetDateLogFileName(const int pass);
	static std::string GetNowString();

	static std::string ConvertRGB2Hex(int r , int g , int b);

	static std::string ConvertDec2Hex(int value)
	{ 
		const int base = 16;
		std::string buf;
		int i = 30; 
		buf = ""; 
		for(; value && i ; --i, value /= base) 
			buf = "0123456789abcdef"[value % base] + buf; 

		return buf;
	}

	static int GetPassedSecFromString(const std::string& time_str);
	static int GetPassedMinInLastHourFromString(const std::string& time_str);

	static std::string GetExt(const std::string& path)
	{
		std::string ext = "";
		int pos = path.rfind("."); 
		if(pos != -1)
		{
			ext = path.substr(pos);
		}
		return ext;
	}


	static int DivideVectorBySize(const int limit_size , const string_vector& org , std::vector<string_vector>& out); 

};


class PROCESS : public ACE_Task<ACE_MT_SYNCH>
{
public:

	bool stop;
	PROCESS()
	{
		stop = false;
	}

	virtual ~PROCESS()
	{
		stop = true;
		this->wait();
	}
	int svc(void);

public:

	static void AddPid(int pid);
	static void DelPid(int pid);

	static void Clear();

	static std::vector<_PROCESS_INFO> g_VecPid;
	static ACE_Thread_Mutex	g_ProcessLock;	
	static _RESULT_TYPE Execute(_PROCESS_TYPE type ,const std::string& cmd , const bool noOutput = true);
	static _RESULT_TYPE Execute2(_PROCESS_TYPE type ,const std::string& cmd , const bool noOutput = true);
	static _RESULT_TYPE Execute(const std::string& cmd , std::string& outstring); 

	static void DeleteTempFiles(const std::string& job_id = "");

	static int GetFilesInDirectory(std::vector<std::string>& vecFiles , const std::string& directory , const std::string& search_string = "");

#ifndef ACE_WIN32
	static int handle_signal (int signum);
	static void InitSignal();
#endif

};

#define LOG_DATA_SIZE 4
class _LOG_DATA
{
	
public:
	_LOG_TYPE type;
	_LOG_MODE mode;
	std::string str_value[LOG_DATA_SIZE];
	int int_value[LOG_DATA_SIZE];
	double double_value[LOG_DATA_SIZE];
	bool bool_value[LOG_DATA_SIZE];

	_LOG_DATA(){};
	_LOG_DATA(const _LOG_DATA& ld)
	{
		*this = ld;
	}

	const _LOG_DATA& operator=(const _LOG_DATA& ld)
	{
		if (this != &ld) 
		{
			this->type = ld.type;
			this->mode = ld.mode;

			for(int i = 0 ; i < LOG_DATA_SIZE ; i ++)
			{
				this->str_value[i] = ld.str_value[i];
				this->int_value[i] = ld.int_value[i];
				this->bool_value[i] = ld.bool_value[i];
				this->double_value[i] = ld.double_value[i];
			}
	

		}
		return *this;
	}


};


class LOG : public ACE_Task<ACE_MT_SYNCH> 
{
private:
	static LOG g_Log;
	std::vector<_LOG_DATA> m_vecLogData;
	bool m_bStop;

	int Insert(const _LOG_DATA&ld);

public:

	ACE_Thread_Mutex m_Lock;	

	LOG()
	{
		m_bStop = false;
	}

	~LOG()
	{
		m_bStop = true;
		this->wait();
	}

	int svc();



public:

	static void Start()
	{
		g_Log.activate();
	}

	static void Stop()
	{
		g_Log.m_bStop = true;
		g_Log.wait();
	}


	static int PushProcessLog(const _LOG_MODE mode , const std::string& content);	
	static int PushJobLog(const _LOG_MODE mode , const std::string& job_id ,const std::string& content);  
	static int PushJobLog(const _LOG_MODE mode ,const std::string& job_id ,const double duration , const int rendering_time);  
	static int PushObjectLog(const std::string& job_id , const std::string& filterId, const std::string& effectIdList, const std::string& soundId);
	static int PushScalingLog(const _LOG_MODE mode ,const int waiting ,  const int changed , const int total);
	static int PushEC2Log(const _LOG_MODE mode , const std::string& ec2_id , const bool start);

	static bool SendSMS(const std::string& msg , const _LOG_MODE mode = _INFO);

private:
	static bool InsertLogData(const _LOG_DATA& ld);

	static bool WriteLog2File(const _LOG_TYPE type ,const _LOG_MODE mode , const std::string& content , const int pass = 0);
	static bool InsertProcessLog2DB(const _LOG_MODE mode , const std::string& content);
	static bool InsertJobLog2DB(const _LOG_MODE mode , const std::string& job_id , double duration , int rendering_time , const std::string& content);
	static bool InsertObjectLog2DB(const std::string& job_id  , const std::string& filterId , const std::string& effectIdList , const std::string& soundId);
	static bool InsertScalingLog2DB(const _LOG_MODE mode , int waiting , int changed , int total);
	static bool InsertEC2Log2DB(const _LOG_MODE mode , const std::string& ec2_id , bool start);

	static bool WriteProcessLog(const _LOG_MODE mode , const std::string& content);	
	static bool WriteJobLog(const _LOG_MODE mode ,const std::string& job_id ,const double duration , const int rendering_time, const std::string& content);
	static bool WriteObjectLog(const std::string& job_id , const std::string& filterId , const std::string& effectIdList , const std::string& soundId);
	static bool WriteScalingLog(const _LOG_MODE mode , const int waiting , const int changed , const int total);
	static bool WriteEC2Log(const _LOG_MODE mode , const std::string& ec2_id , const bool start);


	static std::string GetLogFilePath(const _LOG_TYPE type , const int pass = 0);

};

class _COLOR
{
public:
	int red;
	int green;
	int blue;


public:


	bool IsValid()
	{
		return 255 >= red && red >= 0 
			 && 255 >= green && green >= 0
			 && 255 >= blue && blue >= 0 ;
	}

	_COLOR()
	{
		red = green = blue = -1;
	}


	_COLOR(int r , int g , int b)
	{
		Set(r , g , b);
	}


	void Set(int r , int g , int b)
	{
		red = r;
		green = g;
		blue = b;
	}

	const _COLOR& operator=(const _COLOR& c)
	{
		if (this != &c) 
		{
			Set(c.red , c.green , c.blue);
		}
		return *this;
	}

	std::string GetHexString()
	{
		return MATH::ConvertRGB2Hex(this->red , this->green , this->blue);
	}

};

class ReservedInfo
{
public :
	_JOB_INFO job_info;
	_WORK_RESULT result;


	ReservedInfo(const _JOB_INFO& job_info)
	{
		this->job_info = job_info;
	}


	ReservedInfo(const _JOB_INFO& job_info , const _WORK_RESULT& result)
	{
		this->job_info = job_info;
		this->result = result;
	}

	const ReservedInfo& operator=(const ReservedInfo & info)
	{
		if (this != &info) 
		{
			this->job_info = info.job_info;
			this->result = info.result;
		}
		return *this;
	}

	std::string GetJobId()
	{
		return this->job_info.GetJobId();
	}

	bool IsValid()
	{
		return job_info.IsValid();
	}

};

#endif
